//
// Created by hkkzzxz on 24-9-2.
//

#include <json/json.h>
#include <ctime>
#include <iomanip>
#include <random>

#include "EmployeeService.h"
#include "RedisDatabaseModel.h"
#include "Security.h"
#include "MySQLDatabaseModel.h"
#include "Employee/EmployeeModifyPassword.h"
#include "EmployeeSetting.h"
#include "SendHttp.h"
#include "EmployeeFaceFeatures.h"
#include "EmployeeTodayAttendance.h"
#include "EmployeeAttendance.h"
#include "EmployeeGetName.h"
#include "EmployeeFingerprint.h"

bool EmployeeService::employRegister(const std::string &id, const std::string &name, const std::string &phoneNumber,
                                     const std::string &password) {
    // 判断管理员是否已经添加此员工
    auto redisDatabaseModel = std::make_unique<RedisDatabaseModel>();
    if (!redisDatabaseModel->exists(id)) {
        return false;
    }
    auto dataStr = redisDatabaseModel->get(id);
    Json::Value root;
    Json::Reader reader;

    if (!reader.parse(dataStr, root)) {
        return false;
    }
    auto redisName = root["name"].asString();
    auto redisPhoneNumber = root["phone_number"].asString();
    if (redisName != name || redisPhoneNumber != phoneNumber) {
        return false;
    }
    // 生成用户的盐值以及加密密码
    auto security = std::make_unique<Security>();
    std::string salt = security->generateSalt();
    std::string hashPassword = security->hashPassword(password, salt);

    // 写入MySQL数据库
    std::string update = "UPDATE user SET salt = ?, password = ? WHERE id = ?";
    std::vector<std::string> params = {salt, hashPassword, id};
    auto mysqlDatabaseModel = std::make_unique<MySQLDatabaseModel>();
    if (!mysqlDatabaseModel->update(update, params)) {
        return false;
    }
    std::string insert = "INSERT INTO employee (id, phone_number) VALUES (?, ?)";
    params = {id, phoneNumber};
    if (!mysqlDatabaseModel->insert(insert, params)) {
        return false;
    }
    // 删除redis中的数据并返回成功
    if (redisDatabaseModel->del(id)) {
        return true;
    }
    return false;
}

bool EmployeeService::forgetPassword(const std::string &id, const std::string &name, const std::string &phoneNumber,
                                     const std::string &password) {
    // 查询职工表里面是否有该员工
    std::string query = "SELECT * FROM employee WHERE id = ? AND phone_number = ?";
    std::vector<std::string> params = {id, phoneNumber};
    auto mysqlDatabaseModel = std::make_unique<MySQLDatabaseModel>();
    if (!mysqlDatabaseModel->queryBool(query, params)) {
        return false;
    }

    // 生成用户的盐值以及加密新密码
    auto security = std::make_unique<Security>();
    std::string salt = security->generateSalt();
    std::string hashPassword = security->hashPassword(password, salt);

    // 重置密码
    std::string update = "UPDATE user SET salt = ?, password = ? WHERE id = ? AND name = ?";
    params = {salt, hashPassword, id, name};
    if (mysqlDatabaseModel->update(update, params)) {
        return true;
    }
    return false;
}

bool EmployeeService::modifyPhoneNumber(const std::string &id, const std::string &phoneNumber,
                                        const std::string &newPhoneNumber) {
    // 查询旧手机号是否正确
    std::string query = "SELECT * FROM employee WHERE id = ? AND phone_number = ?";
    std::vector<std::string> params = {id, phoneNumber};
    auto mysqlDatabaseModel = std::make_unique<MySQLDatabaseModel>();
    if (!mysqlDatabaseModel->queryBool(query, params)) {
        return false;
    }

    // 重置手机号
    std::string update = "UPDATE employee SET phone_number = ? WHERE id = ?";
    params = {newPhoneNumber, id};
    if (mysqlDatabaseModel->update(update, params)) {
        return true;
    }
    return false;
}

bool
EmployeeService::modifyPassword(const std::string &id, const std::string &password, const std::string &newPassword) {
    // 查询旧密码是否正确
    std::string query = "SELECT salt, password FROM user WHERE id = ?";
    std::vector<std::string> params = {id};
    auto mysqlDatabaseModel = std::make_unique<MySQLDatabaseModel>();
    auto employeeModifyPassword = mysqlDatabaseModel->queryModel<EmployeeModifyPassword>(query, params);
    if (employeeModifyPassword.empty()) {
        return false;
    }
    auto security = std::make_unique<Security>();
    std::string hashPassword = security->hashPassword(password, employeeModifyPassword.front()->getSalt());
    if (hashPassword != employeeModifyPassword.front()->getPassword()) {
        return false;
    }

    // 生成用户的盐值以及加密新密码
    std::string salt = security->generateSalt();
    std::string newHashPassword = security->hashPassword(newPassword, salt);

    // 重置密码
    std::string update = "UPDATE user SET salt = ?, password = ? WHERE id =?";
    params = {salt, newHashPassword, id};
    if (mysqlDatabaseModel->update(update, params)) {
        return true;
    }
    return false;
}

bool EmployeeService::attendance(const std::string &id) {
    auto mysqlDatabaseModel = std::make_unique<MySQLDatabaseModel>();
    // 查询考勤规则表查看该员工的签到和签退时间
    std::string query = "SELECT morning_start_time, evening_end_time FROM attendance_settings WHERE employee_id = ?";
    std::vector<std::string> params = {id};
    auto employeeSetting = mysqlDatabaseModel->queryModel<EmployeeSetting>(query, params);
    if (employeeSetting.empty()) {
        return false;
    }
    std::string monringStartTime = employeeSetting.front()->getMorning();
    std::string eveningEndTime = employeeSetting.front()->getEvening();

    // 先查询记录表中是否用今天的记录，若有则是签退，没有则是签退
    time_t now = time(nullptr);
    tm *ltm = localtime(&now);
    std::string currentDate = std::to_string(1900 + ltm->tm_year) + "-" +
                              std::to_string(1 + ltm->tm_mon) + "-" +
                              std::to_string(ltm->tm_mday);
    std::string currentTime = std::to_string(ltm->tm_hour) + ":" +
                              std::to_string(ltm->tm_min) + ":" +
                              std::to_string(ltm->tm_sec);
    query = "SELECT * FROM attendance_records WHERE employee_id = ? AND date = ?";
    params = {id, currentDate};

    if (!mysqlDatabaseModel->queryBool(query, params)) {
        // 签到
        std::string late = currentTime > monringStartTime ? "1" : "0";
        std::string insert = "INSERT INTO attendance_records (employee_id, check_in_time, date, late) VALUES (?, ?, ?, ?)";
        params = {id, currentTime, currentDate, late};
        if (mysqlDatabaseModel->insert(insert, params)) {
            return true;
        }
    } else {
        // 签退
        std::string leaverEarly = currentTime < eveningEndTime ? "1" : "0";
        std::string update = "UPDATE attendance_records SET check_out_time = ?, leave_early = ? WHERE employee_id = ?";
        params = {currentTime, leaverEarly, id};
        if (mysqlDatabaseModel->update(update, params)) {
            return true;
        }
    }
    return false;
}

std::string EmployeeService::generateFingerprintID(const std::string &id) {
    auto mysqlDatabaseModel = std::make_unique<MySQLDatabaseModel>();
    // 查询是否已经存在该员工
    std::string query = "SELECT * FROM employee WHERE id = ?";
    std::vector<std::string> params = {id};
    auto employeeFingerprint = mysqlDatabaseModel->queryModel<EmployeeFingerprint>(query, params);
    if (employeeFingerprint.empty()) {
        return "";
    }

    // 判断是否已经存在ID
    if (!employeeFingerprint.front()->getFingerprintId().empty()) {
        return employeeFingerprint.front()->getFingerprintId();
    }

    // 生成指纹ID
    std::string fingerprintID;
    do {
        std::random_device rd;
        std::mt19937 rng(rd());
        std::uniform_int_distribution<int> dist(0, 99);
        fingerprintID = std::to_string(dist(rng));
        query = "SELECT * FROM employee WHERE fingerprint_id = ?";
        params = {fingerprintID};
    } while (mysqlDatabaseModel->queryBool(query, params));

    std::string update = "UPDATE employee SET fingerprint_id = ? WHERE id = ?";
    params = {fingerprintID, id};
    if (!mysqlDatabaseModel->update(update, params)) {
        return "";
    }
    return fingerprintID;
}

std::string EmployeeService::fingerprintAttendance(const std::string &fingerprintID) {
    auto mysqlDatabaseModel = std::make_unique<MySQLDatabaseModel>();
    // 根据指纹ID的查询员工ID
    std::string query = "SELECT * FROM employee WHERE fingerprint_id = ?";
    std::vector<std::string> params = {fingerprintID};
    auto employeeFingerprint = mysqlDatabaseModel->queryModel<EmployeeFingerprint>(query, params);
    if (employeeFingerprint.empty()) {
        return "";
    }
    auto id = employeeFingerprint.front()->getId();
    if (id.empty()) {
        return "";
    }
    if (!attendance(id)) {
        return "";
    }
    return id;
}

bool EmployeeService::uploadAttendancePhoto(const std::string &id, const std::string &photo) {
    // 发送http请求Python的模型进行处理
    auto httpSend = std::make_unique<SendHttp>();
    http::request<http::dynamic_body> req{http::verb::post, "/face_encoding", 11};
    // 设置请求头部为multipart/form-data
    std::string boundary = "----WebKitFormBoundary7MA4YWxkTrZu0gW";
    req.set(http::field::content_type, "multipart/form-data; boundary=" + boundary);
    // 构建form-data请求体
    std::ostringstream bodyStream;
    bodyStream << "--" << boundary << "\r\n";
    bodyStream << "Content-Disposition: form-data; name=\"image\"; filename=\"image.jpg\"\r\n";
    bodyStream << "Content-Type: image/jpeg\r\n\r\n";
    bodyStream << photo << "\r\n";
    bodyStream << "--" << boundary << "--\r\n";

    // 将请求体添加到请求中
    boost::beast::ostream(req.body()) << bodyStream.str();
    req.prepare_payload();

    auto response = httpSend->sendRequest(req);
    // 请求错误
    if (response.result() != http::status::ok) {
        return false;
    }

    Json::Value srcRoot;
    Json::Reader reader;
    auto bodyStr = boost::beast::buffers_to_string(response.body().data());
    bool parsingSuccessful = reader.parse(bodyStr, srcRoot);
    if (!parsingSuccessful) {
        return false;
    }
    std::string faceFeatures = srcRoot["face_encoding"].toStyledString();

    // 写入MySQL数据库
    std::string insert = "INSERT INTO employee_face_features (id, face_features) VALUES (?, ?)";
    std::vector<std::string> params = {id, faceFeatures};
    auto mysqlDatabaseModel = std::make_unique<MySQLDatabaseModel>();
    if (mysqlDatabaseModel->insert(insert, params)) {
        return true;
    }
    return false;
}

std::string EmployeeService::facialAttendance(const std::string &photo) {
    // 从MySQL数据库里提取出所有人的人脸信息
    std::string query = "SELECT * FROM employee_face_features";
    std::vector<std::string> params = {};
    auto mysqlDatabaseModel = std::make_unique<MySQLDatabaseModel>();
    auto employeeFaceFeatures = mysqlDatabaseModel->queryModel<EmployeeFaceFeatures>(query, params);
    if (employeeFaceFeatures.empty()) {
        return "";
    }
    Json::Value data;
    Json::Reader reader;
    for (auto &i: employeeFaceFeatures) {
        Json::Value faceFeatures;
        if (!reader.parse(i->getFaceFeatures(), faceFeatures)) {
            continue;
        }
        data[i->getId()] = faceFeatures;
    }
    std::string dataStr = data.toStyledString();

    // 发送http请求Python的模型进行处理
    auto httpSend = std::make_unique<SendHttp>();
    http::request<http::dynamic_body> req{http::verb::post, "/recognize_face", 11};
    // 设置请求头部为multipart/form-data
    std::string boundary = "----WebKitFormBoundary7MA4YWxkTrZu0gW";
    req.set(http::field::content_type, "multipart/form-data; boundary=" + boundary);
    // 构建form-data请求体
    std::ostringstream bodyStream;
    bodyStream << "--" << boundary << "\r\n";
    bodyStream << "Content-Disposition: form-data; name=\"image\"; filename=\"image.jpg\"\r\n";
    bodyStream << "Content-Type: image/jpeg\r\n\r\n";
    bodyStream << photo << "\r\n";
    bodyStream << "--" << boundary << "\r\n";
    bodyStream << "Content-Disposition: form-data; name=\"data\"\r\n\r\n";
    bodyStream << dataStr << "\r\n";
    bodyStream << "--" << boundary << "--\r\n";
    // 将请求体添加到请求中
    boost::beast::ostream(req.body()) << bodyStream.str();
    req.prepare_payload();

    auto response = httpSend->sendRequest(req);
    // 请求错误
    if (response.result() != http::status::ok) {
        return "";
    }
    Json::Value srcRoot;
    auto bodyStr = boost::beast::buffers_to_string(response.body().data());
    bool parsingSuccessful = reader.parse(bodyStr, srcRoot);
    if (!parsingSuccessful) {
        return "";
    }
    std::string id = srcRoot["recognized_id"].asString();

    // 调用上面的考勤来执行
    if (attendance(id)) {
        return id;
    }
    return "";
}

std::string EmployeeService::checkTodayAttendance(const std::string &id) {
    // 获取今日日期
    time_t now = time(nullptr);
    tm *ltm = localtime(&now);
    std::string currentDate = std::to_string(1900 + ltm->tm_year) + "-" +
                              std::to_string(1 + ltm->tm_mon) + "-" +
                              std::to_string(ltm->tm_mday);

    // 从MySQL考勤记录表中今日数据
    std::string query = "SELECT * FROM attendance_records WHERE employee_id = ? AND date = ?";
    std::vector<std::string> params = {id, currentDate};
    auto mysqlDatabaseModel = std::make_unique<MySQLDatabaseModel>();
    auto employTodayAttendance = mysqlDatabaseModel->queryModel<EmployeeTodayAttendance>(query, params);
    if (employTodayAttendance.empty()) {
        return "";
    }

    Json::Value root;
    root["check_in_time"] = employTodayAttendance.front()->getCheckInTime();
    root["check_out_time"] = employTodayAttendance.front()->getCheckOutTime();
    if (employTodayAttendance.front()->isLate() && !employTodayAttendance.front()->isLeaveEarly()) {
        root["status"] = "late";
    } else if (!employTodayAttendance.front()->isLate() && employTodayAttendance.front()->isLeaveEarly()) {
        root["status"] = "leave early";
    } else if (employTodayAttendance.front()->isLate() && employTodayAttendance.front()->isLeaveEarly()) {
        root["status"] = "late and leave early";
    } else {
        root["status"] = "normal";
    }
    return root.toStyledString();
}

std::string EmployeeService::checkAttendance(const std::string &id) {
    // 从MySQL考勤记录表中读取考勤数据
    std::string query = "SELECT * FROM attendance_records WHERE employee_id = ?";
    std::vector<std::string> params = {id};
    auto mysqlDatabaseModel = std::make_unique<MySQLDatabaseModel>();
    auto employAttendance = mysqlDatabaseModel->queryModel<EmployeeAttendance>(query, params);
    if (employAttendance.empty()) {
        return "";
    }

    // 循环读取为数组
    Json::Value data;
    for (auto &i: employAttendance) {
        Json::Value temp;
        temp["date"] = i->getDate();
        temp["check_in_time"] = i->getCheckInTime();
        temp["check_out_time"] = i->getCheckOutTime();
        if (i->isLate() && !i->isLeaveEarly()) {
            temp["status"] = "late";
        } else if (i->isLate() && i->isLeaveEarly()) {
            temp["status"] = "leave early";
        } else if (i->isLate() && i->isLeaveEarly()) {
            temp["status"] = "late and leave early";
        } else {
            temp["status"] = "normal";
        }
        data.append(temp);
    }
    return data.toStyledString();
}

std::string EmployeeService::getName(const std::string &id) {
    std::string query = "SELECT name FROM user WHERE id = ?";
    std::vector<std::string> params = {id};
    auto mysqlDatabaseModel = std::make_unique<MySQLDatabaseModel>();
    auto employeeInformation = mysqlDatabaseModel->queryModel<EmployeeGetName>(query, params);

    if (employeeInformation.empty()) {
        return "";
    }
    for (auto &i: employeeInformation) {
        return i->getName();
    }
    return "";
}
